You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

245 lines
7.6 KiB

<script setup lang="ts">
/**
* Order Success Page (/order/success/[orderId])
*
* Features:
* - Requires authentication (middleware: auth)
* - Fetches order details from /api/orders/[orderId]
* - Validates order belongs to user (server-side)
* - Validates order status is 'completed'
* - Shows success message and animation
* - Shows order number
* - Shows OrderSummary component (read-only)
* - Links to homepage and product pages
*/
definePageMeta({
middleware: 'auth',
layout: 'default',
})
const route = useRoute()
const orderId = computed(() => route.params.orderId as string)
// Get cart composable to refresh cart state
const { fetchCart } = useCart()
// Order data
const order = ref<any>(null)
const isLoading = ref(false)
const error = ref<string | null>(null)
// Fetch order details
async function fetchOrder() {
if (!orderId.value) return
isLoading.value = true
error.value = null
try {
order.value = await $fetch(`/api/orders/${orderId.value}`)
// Check order status
if (order.value.status !== 'completed') {
error.value = `Diese Bestellung wurde noch nicht abgeschlossen. Status: ${order.value.status}`
// Redirect to confirmation page if still pending
if (order.value.status === 'pending') {
setTimeout(() => {
navigateTo(`/order/confirm/${orderId.value}`)
}, 2000)
}
} else {
// Order completed successfully - refresh cart to show it's empty
await fetchCart()
}
} catch (err: any) {
console.error('Failed to fetch order:', err)
if (err.statusCode === 404) {
error.value = 'Bestellung nicht gefunden'
} else if (err.statusCode === 403) {
error.value = 'Du hast keine Berechtigung, diese Bestellung zu sehen'
} else {
error.value = 'Fehler beim Laden der Bestellung'
}
// Redirect to homepage after 3 seconds
setTimeout(() => {
navigateTo('/')
}, 3000)
} finally {
isLoading.value = false
}
}
// Fetch order on mount
onMounted(() => {
fetchOrder()
})
</script>
<template>
<div>
<CommonHeader />
<div class="container mx-auto px-4 py-8 max-w-4xl">
<!-- Error Alert -->
<Alert v-if="error" variant="destructive" class="mb-6">
<AlertTitle>Fehler</AlertTitle>
<AlertDescription>{{ error }}</AlertDescription>
</Alert>
<!-- Loading State -->
<div v-if="isLoading" class="text-center py-12">
<div
class="animate-spin rounded-full h-12 w-12 border-4 border-white/20 border-t-white mx-auto mb-4"
/>
<p class="text-white/60">Lade Bestellung...</p>
</div>
<!-- Success Content -->
<div v-else-if="order && order.status === 'completed'" class="space-y-8">
<!-- Success Header with Animation -->
<div class="text-center space-y-4 py-8">
<!-- Success Icon (animated checkmark) -->
<div class="flex justify-center mb-6">
<div
class="rounded-full bg-green-500/20 p-6 border-4 border-green-500/50 animate-pulse"
>
<svg
class="w-16 h-16 text-green-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7"
></path>
</svg>
</div>
</div>
<!-- Success Message -->
<h1 class="text-4xl font-bold text-white mb-2">
Vielen Dank für deine Bestellung!
</h1>
<p class="text-xl text-white/70">Deine Bestellung wurde erfolgreich abgeschlossen.</p>
<!-- Order Number -->
<div class="inline-block mt-4 px-6 py-3 bg-white/5 rounded-lg border border-white/10">
<p class="text-sm text-white/60">Bestellnummer</p>
<p class="text-2xl font-mono font-bold text-experimenta-accent">
{{ order.orderNumber }}
</p>
</div>
</div>
<!-- Next Steps Info -->
<Alert class="border-blue-500/50 bg-blue-500/10">
<div class="flex items-start gap-3">
<svg
class="w-5 h-5 text-blue-400 mt-0.5 flex-shrink-0"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<div>
<AlertTitle class="text-blue-400">Wie geht es weiter?</AlertTitle>
<AlertDescription class="text-blue-100/90 space-y-2">
<p>
Du erhältst in Kürze eine Bestätigungs-E-Mail mit allen Details zu deiner
Bestellung.
</p>
<p>
Deine Makerspace-Jahreskarte wird bearbeitet und steht dir bald zur
Verfügung.
</p>
</AlertDescription>
</div>
</div>
</Alert>
<!-- Order Summary Card -->
<Card class="p-6">
<OrderSummary :order="order" :show-address="true" />
</Card>
<!-- Action Buttons -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<NuxtLink to="/">
<Button
variant="outline"
class="w-full border-white/20 hover:bg-white/10 text-white"
size="lg"
>
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
></path>
</svg>
Zurück zur Startseite
</Button>
</NuxtLink>
<NuxtLink to="/experimenta">
<Button
class="w-full bg-gradient-button bg-size-300 bg-left hover:bg-right transition-all duration-300 font-bold text-white shadow-lg hover:shadow-2xl"
size="lg"
>
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
></path>
</svg>
Weitere Produkte kaufen
</Button>
</NuxtLink>
</div>
<!-- Support Info -->
<div class="text-center pt-4 space-y-2">
<p class="text-sm text-white/60">
Fragen zu deiner Bestellung? Kontaktiere uns gerne:
</p>
<a
href="mailto:info@experimenta.science"
class="text-sm text-experimenta-accent hover:underline"
>
info@experimenta.science
</a>
</div>
</div>
</div>
</div>
</template>